package com.boolib.animate.commons.base;




import com.boolib.animate.commons.base.face.*;
import com.boolib.animate.commons.exception.ItemNotFoundException;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;


import java.lang.reflect.ParameterizedType;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author nier
 * @create 2020-02-19 17:33
 */

public class BaseCurdService<T extends BaseEntity> implements BaseSqlQueryService<T>, BaseSqlQueryExampleService<T>, BaseSqlSaveService<T>, BaseSqlDeleteService<T>, BaseSqlUpdateService<T> {

    private Integer enable =  0;
    private Integer disable =  1;

    @Autowired
    private BaseMapper<T> baseMapper;

    private T getT(){
        Class<T> clazz= (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        throw new RuntimeException();
    }


    @Transactional
    @Override
    public T save(T t){
        final LocalDateTime now = LocalDateTime.now();
        t.setCreateTime(now);
        t.setUpdateTime(now);
        t.setIsDel(enable);
        t.setShowStatus(enable);
        baseMapper.insert(t);
        return t;
    }

    @Transactional
    @Override
    public T saveSelective(T t){
        final LocalDateTime now = LocalDateTime.now();
        t.setCreateTime(now);
        t.setUpdateTime(now);
        t.setIsDel(enable);
        t.setShowStatus(enable);
        baseMapper.insertSelective(t);
        return t;
    }


    @Transactional
    @Override
    public List<T> saveBatch(List<T> t){
        final LocalDateTime now = LocalDateTime.now();
        t.forEach((item)->{
            item.setCreateTime(now);
            item.setUpdateTime(now);
            item.setIsDel(enable);
            item.setShowStatus(enable);
        });
        baseMapper.insertList(t);
        return t;
    }


    @Transactional
    @Override
    public void deleteById(Long id){
        queryById(id);
        baseMapper.deleteByPrimaryKey(id);
    }


    @Transactional
    @Override
    public void delete(T t){
        baseMapper.delete(t);
    }



    @Transactional
    @Override
    public void deleteByExample(Example example){
        baseMapper.deleteByExample(example);
    }


    @Transactional
    @Override
    public void deleteByBatch(List<Long> ids){
        baseMapper.deleteByIdList(ids);
    }

    @Transactional
    @Override
    public void deleteSoftById(Long id) {
        final T t = queryById(id);
        t.setIsDel(disable);
        baseMapper.updateByPrimaryKeySelective(t);
    }

    @Transactional
    @Override
    public void deleteSoft(T t) {
        final List<T> query = query(t);
        final LocalDateTime now = LocalDateTime.now();
        query.forEach((item)->{
            item.setIsDel(disable);
            item.setUpdateTime(now);
            baseMapper.updateByPrimaryKeySelective(item);
        });
    }

    @Transactional
    @Override
    public void deleteSoftByExample(Example example) {
        final LocalDateTime now = LocalDateTime.now();
        final List<T> query = queryByExample(example);
        query.forEach((item)->{
            item.setIsDel(disable);
            item.setUpdateTime(now);
            baseMapper.updateByPrimaryKeySelective(item);
        });
    }

    @Transactional
    @Override
    public void deleteSoftByBatch(List<Long> ids) {
        final LocalDateTime now = LocalDateTime.now();
        final List<T> query = queryByIds(ids);
        query.forEach((item)->{
            item.setIsDel(disable);
            item.setUpdateTime(now);
            baseMapper.updateByPrimaryKeySelective(item);
        });
    }

    @Transactional
    @Override
    public  T updateByIdNoQuery(T t) {


        t.setUpdateTime(LocalDateTime.now());
        baseMapper.updateByPrimaryKey(t);
        return queryById(t.getId());
    }




    @Transactional
    @Override
    public T updateById(T t) {

        queryByIdThrow(t.getId());
        t.setUpdateTime(LocalDateTime.now());
        baseMapper.updateByPrimaryKey(t);
        return      queryById(t.getId());
    }

    @Transactional
    @Override
    public T updateById(Long id, T t) {
        t.setId(id);
        queryById(id);
        t.setUpdateTime(LocalDateTime.now());
        baseMapper.updateByPrimaryKey(t);
        return queryById(id);
    }



    @Transactional
    @Override
    public List<T> updateByExample(T t, Example example) {
        t.setUpdateTime(LocalDateTime.now());
        baseMapper.updateByExample(t,example);
        final List<T> query = query(t);

        return query;
    }

    @Transactional
    @Override
    public List<T> updateByExampleSelective(T t, Example example) {

        t.setUpdateTime(LocalDateTime.now());

        baseMapper.updateByExampleSelective(t,example);

        final List<T> query = query(t);

        return query;
    }

    @Transactional
    @Override
    public T  updateByPrimaryKeySelective(T t) {

        queryById(t.getId());
        t.setUpdateTime(LocalDateTime.now());
        baseMapper.updateByPrimaryKeySelective(t);
        return  queryById(t.getId());
    }

    @Transactional
    @Override
    public T  updateByPrimaryKeySelective(Long id, T t) {
        t.setId(id);
        queryById(id);
        baseMapper.updateByPrimaryKeySelective(t);
        return  queryById(id);
    }









    @Override
    public T queryOne(T t){
        t.setIsDel(enable);
        return  baseMapper.selectOne(t) ;
    }
    @Override
    public T queryOneThrow(T t){
        t.setIsDel(enable);
        return Optional.ofNullable( baseMapper.selectOne(t)).orElseThrow(ItemNotFoundException::new);
    }

    @Override
    public T queryById(Long id){
        final T t = getT();
        t.setId(id);
        return queryOne(t);
    }

    @Override
    public T queryByIdThrow(Long id){
        final T t = getT();
        t.setId(id);
        return queryOneThrow(t);
    }




    @Override
    public List<T> query(T t){
        t.setIsDel(enable);
        return Optional.ofNullable( baseMapper.select(t)).get();
    }



    @Override
    public List<T> queryAll(){
        final T t = getT();
        t.setIsDel(enable);
        return query(t);

    }


    @Override
    public List<T> queryByIds(List<Long> ids){
        return baseMapper.selectByIdList(ids).stream().filter(t->enable.equals(t.getIsDel())).collect(Collectors.toList());
    }




    @Override
    public PageInfo<T> queryByRowBounds(T t, Integer page, Integer size){
        t.setIsDel(enable);
        PageHelper.startPage(page,size);
        return  PageInfo.of(baseMapper.select(t));
    }


    @Override
    public Integer queryCount(T t){
        t.setIsDel(enable);
        return  baseMapper.selectCount(t) ;
    }



    @Override
    public PageInfo<T> queryByExampleAndRowBounds(Example example, Integer page, Integer size) {
        example.createCriteria().andEqualTo("isDel",enable);
        PageHelper.startPage(page,size);
        return  PageInfo.of(baseMapper.selectByExample(example));
    }

    @Override
    public Integer queryCountByExample(Example example) {
        example.createCriteria().andEqualTo("isDel",enable);
        return  baseMapper.selectCountByExample(example) ;
    }

    @Override
    public  T queryOneByExample(Example example){
        example.createCriteria().andEqualTo("isDel",enable);
        return  baseMapper.selectOneByExample(example);
    }

    @Override
    public T queryOneByExampleThrow(Example example) {
          example.createCriteria().andEqualTo("isDel",enable);
        return Optional.ofNullable( baseMapper.selectOneByExample(example)).orElseThrow(ItemNotFoundException::new);
    }

    @Override
    public  List<T> queryByExample(Example example){
        example.createCriteria().andEqualTo("isDel",enable);
        return Optional.ofNullable( baseMapper.selectByExample(example)).get();
    }




    @Override
    public boolean  existsById(Long id) {
      return   baseMapper.existsWithPrimaryKey(id);

    }



}
